package cn.itrigger.dynamic.sql.structure;

import cn.itrigger.dynamic.sql.render.TableAliasCalculator;

import java.sql.JDBCType;
import java.util.Objects;
import java.util.Optional;

/**
 * @author admin
 * @date 2018/9/20
 **/
public class SqlColumn<T> implements BindableColumn<T> {

    private String name;

    private JDBCType jdbcType;

    private SqlTable sqlTable;

    private String alias;

    protected SqlColumn(Builder builder) {
        this.name = Objects.requireNonNull(builder.name);
        this.sqlTable = Objects.requireNonNull(builder.sqlTable);
        this.jdbcType = builder.jdbcType;
    }

    public String name() {
        return name;
    }

    public SqlTable sqlTable() {
        return sqlTable;
    }

    @Override
    public Optional<JDBCType> jdbcType() {
        return Optional.ofNullable(this.jdbcType);
    }

    @Override
    public SqlColumn<T> as(String alias) {
        this.alias = Objects.requireNonNull(alias);
        return this;
    }

    @Override
    public String renderWithTableAlias(TableAliasCalculator tableAliasCalculator) {
        return tableAliasCalculator.alias(sqlTable).map(this::applyTableAlias).orElseGet(this::name);
    }

    @Override
    public Optional<String> alias() {
        return Optional.ofNullable(this.alias);
    }

    public static Builder withName(String name) {
        Builder builder = new Builder();
        builder.withName(name);
        return builder;
    }

    public static SqlColumn of(String name,SqlTable sqlTable) {
        return withName(name).withTable(sqlTable).build();
    }

    public static SqlColumn of(String name,SqlTable sqlTable,JDBCType jdbcType) {
        return withName(name).withTable(sqlTable).withJdbcType(jdbcType).build();
    }

    private String applyTableAlias(String tableName) {
        return tableName + "." + name;
    }

    public static class Builder {
        private String name;

        private JDBCType jdbcType;

        private SqlTable sqlTable;

        public Builder withTable(SqlTable sqlTable) {
            this.sqlTable = sqlTable;
            return this;
        }

        public Builder withName(String name) {
            this.name = name;
            return this;
        }

        public Builder withJdbcType(JDBCType jdbcType) {
            this.jdbcType = jdbcType;
            return this;
        }

        public SqlColumn build() {
            return new SqlColumn(this);
        }
    }
}
